package com.gcloud.mesh.sign;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.cache.PermissionCodeCache;
import org.jeecg.common.constant.enums.SysLogOperateType;
import org.jeecg.common.constant.enums.SysLogType;
import org.jeecg.common.constant.enums.SysLogUrlOperate;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.LogUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.vo.PermissionsInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.gcloud.mesh.framework.core.SpringUtil;

import cn.hutool.core.convert.Convert;
import lombok.extern.slf4j.Slf4j;

/**
 * 防篡改、防重放攻击过滤器
 */
@Slf4j
//@Component
public class SignAuthFilter implements Filter {

	@Autowired
	private ISysBaseAPI sysBaseAPI;

	private static List<String> exceptUri = new ArrayList<>();

	static {
		exceptUri.add("/mesh-controller/isc/isc_server_url");
		exceptUri.add("/mesh-controller/isc/permissions_compare");
		exceptUri.add("/mesh-controller/isc/get_isc_url");
		exceptUri.add("/mesh-controller/isc/get_db_status");
		exceptUri.add("/mesh-controller/webservice/iscImsService");
		exceptUri.add("/mesh-controller/sys/login");
		exceptUri.add("/mesh-controller/sys/permission/getUserPermissionByToken");
		exceptUri.add("/mesh-controller/sys/logout");
		exceptUri.add("/mesh-controller/cas/client/getCurrentUserName");
		exceptUri.add("/mesh-controller/cas/client/validateLogin");
	}

	@Override
	public void destroy() {
		log.info("销毁 SignAuthFilter");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		// 签名验证开关
		RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
		Object result = redisUtil.get("CloseSigenAuth");
		if (result == null || (result != null && (Boolean) result == true)) {
			filterChain.doFilter(request, response);
			return;
		}
		
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		String url = httpRequest.getRequestURI();

		if (!exceptUri.contains(url)) {

			JSONObject jsonObj = new JSONObject(true);
			Map<String, Object> treeMap = new TreeMap<>();
			Map<String, String[]> params = httpRequest.getParameterMap();
			for (Map.Entry<String, String[]> entry : params.entrySet()) {
				String v[] = entry.getValue();
				Object o = (v.length == 1) ? v[0] : v;
				treeMap.put(entry.getKey(), o);
			}

			Iterator it = treeMap.keySet().iterator();
			while (it.hasNext()) {
				String key = (String) it.next();
				jsonObj.put(key, treeMap.get(key));
			}

			String sign = httpRequest.getHeader("Sign");
			Long timestamp = Convert.toLong(httpRequest.getHeader("Timestamp"));

			if (StringUtils.isEmpty(sign)) {
				returnFail(httpRequest, "签名不允许为空。", response);
				return;
			}

// TODO 不需要判断超时
//			if (timestamp == null) {
//				returnFail(httpRequest,"时间戳不允许为空。", response);
//				return;
//			} else {
//				Long difference = System.currentTimeMillis() - timestamp;
//				if (difference / 1000 > 300) {
//					returnFail(httpRequest,"签名已过期。", response);
//					return;
//				}
//			}

			try {
				boolean accept = true;
				switch (httpRequest.getMethod()) {
				case "GET":
					accept = SignUtil.verifySign(jsonObj, sign, timestamp);
					break;
				case "POST":
				case "PUT":
				case "DELETE":
					accept = SignUtil.verifySign(jsonObj, sign, timestamp);
					break;
				default:
					accept = true;
					break;
				}
				if (accept) {
					filterChain.doFilter(httpRequest, response);
				} else {
					returnFail(httpRequest, "完整性被破坏，请注意数据安全。", response);
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			filterChain.doFilter(request, response);
			return;
		}
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		log.info("初始化 SignAuthFilter");
	}

	private void returnFail(HttpServletRequest request, String msg, ServletResponse response) throws IOException {
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json; charset=utf-8");
		//记录完整性被破坏日志
		LogUtil.log(request, SysLogUrlOperate.errorSecurity);
//		ISysBaseAPI sysBaseAPI = SpringUtil.getBean(ISysBaseAPI.class);
//		String requestUrl = request.getRequestURI().replace("//", "/");
//		if (requestUrl.startsWith("/mesh-controller")) {
//			requestUrl = requestUrl.substring("/mesh-controller".length(), requestUrl.length());
//		}
//		PermissionsInfoVo vo = PermissionCodeCache.getByUrl(requestUrl);
//		Integer logType = SysLogUrlOperate.getOperateTypeByUrl(requestUrl);
//		if(vo != null) {
//			//获取title
//			String title = request.getParameter("title");
//			LogUtil.log(request);
//			if(StringUtils.isNotBlank(title)) {
//				//sysBaseAPI.addLog(vo.getName()+"失败"+"（数据完整性被破坏"+"）", SysLogType.OPERATE, SysLogOperateType.getByType(logType), null, SysLogUrlOperate.errorRemark ,title);
//			}else {
//				//sysBaseAPI.addLog(vo.getName()+"失败"+"（数据完整性被破坏"+"）", SysLogType.OPERATE,  SysLogOperateType.getByType(logType), null, SysLogUrlOperate.errorRemark, null);
//			}			
//		}
		PrintWriter out = response.getWriter();
		String result = JSONObject.toJSONString(msg);
		out.println(result);
		out.flush();
		out.close();
	}

}
